<template>
  <div class="dynamicForm-container">
    <a-row>
      <a-col :span="5">
        <div class="left">
          <div>
            <div class="fs-16 fw-bold mb-10">基础组件</div>
            <Draggable
              class="com-list"
              tag="div"
              :list="basicCom"
              item-key="key"
              draggable=".com-item"
              v-bind="{
                group: {name: 'group', pull: 'clone', put: false},
                sort: false,
                ghostClass: 'ghost'
              }"
            >
              <template #item="{element, index}">
                <div class="com-item mr-10 mb-10">{{ element.label }}</div>
              </template>
            </Draggable>
          </div>
        </div>
      </a-col>
      <a-col :span="14">
        <div class="center">
          <div class="center-header">
            <div class="center-header-btn" @click="goHandle(1)">预览</div>
          </div>
          <a-form
            :layout="formConfig.layout"
            :size="formConfig.size"
            :label-align="formConfig.labelAlign"
          >
            <Draggable
              class="form-list"
              tag="div"
              item-key="key"
              :list="formList"
              draggable=".form-item"
              v-bind="{
                group: 'group',
                ghostClass: 'ghost',
                animation: 200,
                sort: true
              }"
              @add="comAdd"
              @end="dragEnd"
            >
              <template #item="{element, index}">
                <FormItem
                  :item-config="element"
                  :index="index"
                  v-model:active-index="activeIndex"
                  @itemDelete="itemDelete"
                  @itemCopy="itemCopy"
                ></FormItem>
              </template>
            </Draggable>
          </a-form>
        </div>
      </a-col>
      <a-col :span="5">
        <div class="right">
          <ComConfig
            :form-config="formConfig"
            :item-config="activeItem"
          ></ComConfig>
        </div>
      </a-col>
    </a-row>

    <a-modal
      width="40%"
      v-model:open="showPreview"
      title="预览"
      @ok="showPreviewCon"
    >
      <Preview ref="PreviewRef" v-if="showPreview" :data="data_calc"></Preview>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import Draggable from "vuedraggable";
import FormItem from "./FormItem.vue";
import ComConfig from "./ComConfig.vue";
import {basicCom} from "./config";
import {computed, ref, watch} from "vue";
import {config} from "./config";
import Preview from "./Preview.vue";
import {randomString, deepClone} from "@/utils/common";
import {message} from "ant-design-vue";

const props = defineProps({
  data: {
    type: Object,
    default: {
      formList: [],
      formConfig: {}
    }
  }
});

const data_calc = computed(() => {
  let data = {
    formList: deepClone(formList.value),
    formConfig: deepClone(formConfig.value)
  };
  return data;
});

const formList = computed(() => {
  if (props.data && props.data.formList) {
    return props.data.formList;
  } else {
    props.data.formList = [];
    return props.data.formList;
  }
});

const formConfig = computed(() => {
  if (props.data && props.data.formConfig.size) {
    return props.data.formConfig;
  } else {
    props.data.formConfig = config;
    return props.data.formConfig;
  }
});

const activeIndex = ref<number>();
const activeItem = ref<object>();
const showPreview = ref(false);
const PreviewRef = ref();

const comAdd = (element) => {
  let newIndex = element.newIndex;
  let newItem = formList.value[newIndex];
  let cloneNewItem = cloneParam(newItem);
  cloneNewItem.defaultKey = randomString();
  formList.value[newIndex] = cloneNewItem;
  activeIndex.value = newIndex;
};

const dragEnd = (e) => {
  activeIndex.value = e.newIndex;
};

watch(
  activeIndex,
  () => {
    activeItem.value = formList.value[activeIndex.value];
  },
  {deep: true}
);

const cloneParam = (param: any) => {
  return JSON.parse(JSON.stringify(param));
};

const itemDelete = (index) => {
  formList.value.splice(index, 1);
};

const itemCopy = (index) => {
  let item = cloneParam(formList.value[index]);
  item.defaultKey = randomString();
  formList.value.splice(index, 0, item);
};

const goHandle = (type: number) => {
  if (type === 1) {
    showPreview.value = true;
  }
};

const showPreviewCon = async () => {
  const res = await PreviewRef.value.submit();
  message.success("表单数据：" + JSON.stringify(res));
};

const validate = () => {
  if (!formList.value.length) {
    message.error("请选择组件");
    return false;
  }
  return true;
};

defineExpose({
  validate
});
</script>

<style lang="less" scoped>
.dynamicForm-container {
  height: 100%;
  background-color: #fff;

  .ant-row {
    height: 100%;

    .ant-col {
      height: 100%;
    }
  }

  .left {
    height: 100%;

    .com-list {
      display: flex;
      flex-wrap: wrap;

      .com-item {
        height: 30px;
        width: 90px;
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: #f4f6fc;
        border-radius: 2px;
        cursor: move;
        border: 1px solid #f4f6fc;

        &:hover {
          border-color: @primary-color;
        }
      }
    }
  }

  .center {
    height: 100%;
    padding: 0 10px;
    display: flex;
    flex-direction: column;

    .center-header {
      margin-bottom: 14px;
      display: flex;
      justify-content: flex-end;

      .center-header-btn {
        color: @primary-color;
        cursor: pointer;
      }
    }

    :deep(.ant-form) {
      flex: 1;
      border: 2px dashed #dedede;

      .form-list {
        height: 100%;

        .form-item {
          &.ghost {
            background: #f56c6c;
            border: 2px solid #f56c6c;
            outline-width: 0;
            height: 3px;
            box-sizing: border-box;
            font-size: 0;
            content: "";
            overflow: hidden;
            padding: 0;
          }
        }

        .com-item {
          margin-right: 0 !important;

          &.ghost {
            background: #f56c6c;
            border: 2px solid #f56c6c;
            outline-width: 0;
            height: 3px;
            box-sizing: border-box;
            font-size: 0;
            content: "";
            overflow: hidden;
            padding: 0;
          }
        }
      }
    }
  }

  .right {
    height: 100%;
    overflow: hidden auto;
    padding: 0 10px;
  }
}
</style>
